#ifndef xpack_chrono_time
#define xpack_chrono_time
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::chrono_time::inc
#include"define/classify.hpp"
#include"macro/xexport.hpp"
#include"macro/xstruct.hpp"
#include"memop/cmp.hpp"
#include"memop/zeros.hpp"
#pragma pop_macro("xuser")

namespace mixc::chrono_time::inc{
    enum{
        bits_of_millisecond     = 10,
        bits_of_second          = 6,
        bits_of_minute          = 6,

        bits_of_low_3_fields    = bits_of_millisecond + bits_of_second + bits_of_minute,
    };
}

namespace mixc::chrono_time::origin{
    // 允许闰秒的存在
    constexpr uxx allow_leap_second = 60;

    /**
     * @brief 
     * 时间对象，时分秒毫秒
     * 小时可以大于等于 24 表示时间间隔
     * @note
     * 注意当 field_t = u32 时，m_hour 的最大值为 1023，
     * 当小时表示时间间隔时，需要留意溢出问题
     * @tparam field_t 构成时分秒毫秒的类型
     */
    template<class field_t = u32>
    xstruct(
        xtmpl(timex, field_t),
        xproc(m_millisecond, inc::bits_of_millisecond                       , field_t),  // 低位
        xproc(m_second     , inc::bits_of_second                            , field_t),
        xproc(m_minute     , inc::bits_of_minute                            , field_t),
        xproc(m_hour       , xbitsof(field_t) - inc::bits_of_low_3_fields   , field_t),  // 高位，按比较的顺序
        xwhos(inc::classify_t::chrono_time)
    )
        template<class> friend struct timex;

    public:
        xprops()
            xpubget_pubset(millisecond, field_t);
            xpubget_pubset(second, field_t);
            xpubget_pubset(minute, field_t);
            xpubget_pubset(hour, field_t);

            xpubget_pubsetx(total_milisecond, u64){
                xr{
                    auto ms = 
                        u64(xthe.m_millisecond) + 
                        u64(xthe.m_second) * (1000) + 
                        u64(xthe.m_minute) * (60 * 1000) + 
                        u64(xthe.m_hour)   * (60 * 60 * 1000);
                    return ms;
                }
                xw{
                    xthe.m_hour         = (value / (60 * 60 * 1000));
                    value              %= (60 * 60 * 1000);
                    xthe.m_minute       = (value / (60 * 1000));
                    value              %= (60 * 1000);
                    xthe.m_second       = (value / (1000));
                    value              %= (1000);
                    xthe.m_millisecond  = (value);
                }
            };

            xpubgetx(is_valid_when_allow_leap_second, bool){
                xr{ return uxx(xthe.m_minute) <= 59 and uxx(xthe.m_second) <= 60 and uxx(xthe.m_millisecond) <= 999; }
            };

            xpubgetx(is_valid_12h_time_when_allow_leap_second, bool){
                xr{ return 0 < uxx(xthe.m_hour) and uxx(xthe.m_hour) <= 12 and xthe->is_valid_when_allow_leap_second; }
            };

            xpubgetx(is_valid_24h_time_when_allow_leap_second, bool){
                xr{ return 0 <= uxx(xthe.m_hour) and uxx(xthe.m_hour) <= 23 and xthe->is_valid_when_allow_leap_second; }
            };

            xpubgetx(is_valid, bool){
                xr{ return uxx(xthe.m_minute) <= 59 and uxx(xthe.m_second) <= 59 and uxx(xthe.m_millisecond) <= 999; }
            };

            xpubgetx(is_valid_12h_time, bool){
                xr{ return 0 < uxx(xthe.m_hour) and uxx(xthe.m_hour) <= 12 and xthe->is_valid; }
            };

            xpubgetx(is_valid_24h_time, bool){
                xr{ return 0 <= uxx(xthe.m_hour) and uxx(xthe.m_hour) <= 23 and xthe->is_valid; }
            };
        $

        xprops_operator()

    public:
        /**
         * @brief 
         * 通过 chrono/now.hpp 初始化当前时间
         * @tparam now_t chrono/now.hpp 中的 now 符合该约束
         */
        template<inc::is_nowxx now_t>
        constexpr timex(now_t):
            timex(now_t::time()){
        }

        /**
         * @brief
         * 通过与 timex<> 相似的结构初始化该结构体
         * @param value 当前结构的类似物
         */
        template<inc::is_time time_t>
        constexpr timex(time_t const & value) : 
            timex(
                value->hour,
                value->minute,
                value->second,
                value->millisecond
            ){
        }

        constexpr timex(){
            inc::zeros(this, sizeof(the_t));
        }

        /**
         * @brief
         * 通过时分秒毫秒初始化该结构
         * @param hour 时
         * @param minute 分
         * @param second 秒
         * @param millisecond 毫秒
         */
        constexpr timex(field_t hour, field_t minute = 0, field_t second = 0, field_t millisecond = 0) : timex(){
            m_millisecond   = millisecond;
            m_second        = second;
            m_minute        = minute;
            m_hour          = hour;
        }

        /**
         * @brief 
         * 比较两个时间
         * @param value 比较数
         * @return ixx 
         * 当前日期 == value 返回 0
         * 当前日期 >  value 返回正数（不局限于 1）
         * 当前日期 <  value 返回负数（不局限于 -1）
         */
        ixx compare(the_t const & value) const {
            auto left       =
                m_hour      << (inc::bits_of_millisecond + inc::bits_of_second | inc::bits_of_minute) |
                m_minute    << (inc::bits_of_millisecond + inc::bits_of_second) | 
                m_second    << (inc::bits_of_millisecond) | 
                m_millisecond;
            
            auto right      =
                value.m_hour      << (inc::bits_of_millisecond + inc::bits_of_second | inc::bits_of_minute) |
                value.m_minute    << (inc::bits_of_millisecond + inc::bits_of_second) | 
                value.m_second    << (inc::bits_of_millisecond) | 
                value.m_millisecond;
            return left == right ? 0 : left < right ? -1 : 1;
        }

        /**
         * @brief 
         * 时间差
         * @return ixx 
         * 两个时间相差的毫秒数
         */
        friend ixx operator- (the_t const & left, the_t const & right){
            return (ixx)(left->total_milisecond - right->total_milisecond);
        }

        #define xa_args_list       the_t const & left, the_t const & right
        #define xa_invoke          left.compare(right)
        #define xa_is_friend
        #include"macro/xgen.cmp.hpp"
    $

    using time = timex<>;
}

#endif

xexport_space(mixc::chrono_time::origin)
